/*model.go访问table.go包*/
package db

import (
	"encoding/json"
	"errors"
	"../conv"
	"regexp"
	"strings"
	"time"
)

//注意：使用时，继承该结构体，且为数据库字段的属性需增加tag
//例如
/*
 Type User struct{
	Name string `m:"."`
 }
*/

//模型，用于数据库快速建模
type Model struct {
	SessionBase                    //继承session
	pkid      *int32               //主键编号
	pkColum   string               //主键列
	tableName string               //表名
	mapData   map[string]*conv.Val //反射映射的关系
	addTime   *conv.Val
	modTime   *conv.Val
	onlyCols  map[string]bool
	omitCols  map[string]bool
}

//模型初始化
func (this *Model) Init(obj interface{}, sx *Session) *Model {
	this.mapData = make(map[string]*conv.Val)
	this.onlyCols = make(map[string]bool)
	this.omitCols = make(map[string]bool)
	conv.EachStruct(obj, func(v *conv.Val) {
		if this.tableName == "" {
			this.tableName = this.snake(v.StructName())
		}
		k := strings.ToLower(v.Name())
		if v.Tag("db") != "" {
			this.mapData[k] = v
		}
		switch v.Tag("db") {
		case "pk":
			this.pkColum = k
			this.pkid = v.V.Addr().Interface().(*int32)
		case "add":
			this.addTime = v
		case "mod":
			this.modTime = v
		}

	})
	this.session = sx
	return this
}

//
func (this *Model) snake(s string) string {
	re := regexp.MustCompile("([a-z])([A-Z])")
	s = re.ReplaceAllString(s, `$1-$2`)
	return strings.Replace(s, "-", "_", -1)
}

//获取信息，并将值映射到当前结构体上
func (this *Model) Info() (data map[string]string, err error) {
	data, err = this.session.Table(this.tableName).Where("`"+this.pkColum+"`=?", *this.pkid).GetOne()
	this.Bind(data)
	return
}

//映射数据
func (this *Model) Bind(data map[string]string) {
	for k, v := range data {
		k = strings.ToLower(k)
		if d, ok := this.mapData[k]; ok {
			d.Set(v)
		}
	}
}

//根据指定字段名来获取模型信息
func (this *Model) InfoBy(col string) (data map[string]string, err error) {
	col = strings.ToLower(col)
	if val, ok := this.mapData[col]; ok {
		data, err = this.session.Table(this.tableName).Where("`"+col+"`=?", val.Value()).GetOne()
		this.Bind(data)
		return
	}
	return nil, errors.New(col + "not exists.")
}

//添加,返回插入的ID和错误信息
func (this *Model) Add() (id int, e error) {
	if this.addTime != nil {
		now := time.Now().Format("2006-01-02 15:04:05")
		this.addTime.Set(now)
	}
	data := this.getModelData()
	delete(data, this.pkColum)
	i, e := this.session.Table(this.tableName).Insert(data)
	if e == nil {
		*this.pkid = int32(i)
	}
	return int(i),e
}

//必须保存的字段
func (this *Model) Only(cols ...string) *Model {
	for _, col := range cols {
		col := strings.ToLower(col)
		this.onlyCols[col] = true
	}
	return this
}

//忽略保存的字段
func (this *Model) Omit(cols ...string) *Model {
	for _, col := range cols {
		col := strings.ToLower(col)
		this.omitCols[col] = true
	}
	return this
}

//设置默认要保存的字段
func (this *Model) getModelData() H {
	data := make(H)
	onlyLen := len(this.onlyCols)
	for k, v := range this.mapData {
		if this.omitCols[k] {
			continue
		}
		if onlyLen > 0 {
			if this.onlyCols[k] {
				data[k] = v.Value()
			}
		} else {
			data[k] = v.Value()
		}
	}
	return data
}

//修改，可以指定修改哪些字段
func (this *Model) Mod() (n int64,e error) {
	if this.modTime != nil {
		now := time.Now().Format("2006-01-02 15:04:05")
		this.modTime.Set(now)
	}
	data := this.getModelData()
	i, e := this.session.Table(this.tableName).Where("`"+this.pkColum+"`=?", *this.pkid).UpdateOne(data)
	return int64(i),e
}

//删除
func (this *Model) Del() error {
	_, e := this.session.Table(this.tableName).Where("`"+this.pkColum+"`=?", *this.pkid).Delete()
	return e
}

//查询的结果转换为对象
func Res2Struct(in []map[string]string, out interface{}) error {
	if bt, e := json.Marshal(in); e != nil {
		return e
	} else {
		return json.Unmarshal(bt, out)
	}
}
